package org.lecric.wind44.server.service;

import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Properties;

import javax.jdo.PersistenceManager;
import javax.jdo.Query;
import javax.mail.Message;
import javax.mail.MessagingException;
import javax.mail.Session;
import javax.mail.Transport;
import javax.mail.internet.AddressException;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;

import org.apache.commons.beanutils.BeanUtils;
import org.lecric.wind44.client.model.Spot;
import org.lecric.wind44.client.model.SpotInformation;
import org.lecric.wind44.client.model.Spots;
import org.lecric.wind44.client.service.SpotService;
import org.lecric.wind44.server.model.DBSpot;
import org.lecric.wind44.server.model.DBSpotInfo;
import org.lecric.wind44.server.model.DBUtil;

import com.google.appengine.api.datastore.Key;
import com.google.appengine.api.datastore.KeyFactory;
import com.google.appengine.api.users.User;
import com.google.appengine.api.users.UserService;
import com.google.appengine.api.users.UserServiceFactory;
import com.google.gwt.user.server.rpc.RemoteServiceServlet;

/**
 * The server side implementation of the RPC service.
 */
@SuppressWarnings("serial")
public class SpotServiceImpl extends RemoteServiceServlet implements SpotService {

	public Spots getSpots()
	{
		PersistenceManager pm = PMF.get().getPersistenceManager();
		try
		{
			List<Spot> spots=new ArrayList<Spot>();
			for(DBSpot dbSpot: getDBSpots(pm))
			{
				Spot spot = DBUtil.db2pojo(dbSpot);
				spots.add(spot);
				for(DBSpotInfo dbSpotInfo: getInfos(pm, dbSpot.getId()))
				{
					spot.getInfos().add(DBUtil.db2pojo(dbSpotInfo));
				}
			}
			Spots result=new Spots();
			result.setSpots(spots);
			UserService userService = UserServiceFactory.getUserService();
			User currentUser = userService.getCurrentUser();
			if(currentUser!=null)
			{
				result.setUser(currentUser.getNickname());
				result.setAdministrator(userService.isUserAdmin());
			}
			else
				result.setAdministrator(false);
			return result;
		}
		finally
		{
			pm.close();
		}
	}

	@Override
	public void initDB()
	{
		//
		List<Spot> spots=new ArrayList<Spot>();
		String user=DBUtil.toString(UserServiceFactory.getUserService().getCurrentUser());
		int index=0;
		spots.add(createMazerollesSpot(user, index++));
		spots.add(createPontMaheSpot(user, index++));
		PersistenceManager pm = PMF.get().getPersistenceManager();
		// 
		try
		{
			pm.deletePersistentAll(getDBSpots(pm));
			pm.deletePersistentAll(getInfos(pm));
			for(Spot spot: spots)
			{
				DBSpot dbSpot=DBUtil.pojo2db(spot);
				pm.makePersistent(dbSpot);
				for(SpotInformation spotInformation: spot.getInfos())
				{
					DBSpotInfo dbSpotInfo=//new DBSpotInfo(null, spotInformation.getName(), spotInformation.getUrl(), new Date(), true, dbSpot.getId());
						DBUtil.pojo2db(spotInformation, dbSpot.getId());
					pm.makePersistent(dbSpotInfo);
				}
			}
		}
		finally
		{
			pm.close();
		}
	}

	@Override
	public Spot add(Spot spot)
	{
		PersistenceManager pm = PMF.get().getPersistenceManager();
		try
		{
			Spot result = DBUtil.db2pojo(pm.makePersistent(DBUtil.pojo2db(spot)));
			mailNotify("NEW: Spot " + spot.getName());
			return result;
		}
		finally
		{
			pm.close();
		}
	}
	
	@Override
	public void delete(Spot spot)
	{
		PersistenceManager pm = PMF.get().getPersistenceManager();
		try
		{
			pm.deletePersistent(getDBSpot(pm, spot.getId()));
		}
		finally
		{
			pm.close();
		}
	}
	
	@Override
	public void changeProperties(Spot spot) {
		PersistenceManager pm = PMF.get().getPersistenceManager();
		try
		{
			DBSpot dbSpot = getDBSpot(pm, spot.getId());
			String oldName=dbSpot.getName();
			DBSpot newDbSpot=DBUtil.pojo2db(spot);
			BeanUtils.copyProperties(dbSpot, newDbSpot);
//			dbSpot.setLatitude(newDbSpot.getLatitude());
//			dbSpot.setLongitude(newDbSpot.getLongitude());
			dbSpot.setDate(new Date());
			dbSpot.setAuthor(UserServiceFactory.getUserService().getCurrentUser());
			String tip=oldName + " => " + dbSpot.getName();
			mailNotify("CHANGE: Spot " + tip);
		}
		catch (IllegalAccessException e)
		{
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		catch (InvocationTargetException e)
		{
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		finally
		{
			pm.close();
		}
	}
	
	@Override
	public void delete(SpotInformation spotinfo)
	{
		PersistenceManager pm = PMF.get().getPersistenceManager();
		try
		{
			pm.deletePersistent(getInfo(pm, spotinfo.getId()));
		}
		finally
		{
			pm.close();
		}
	}
	
	@Override
	public void changeProperties(SpotInformation spot) {
		PersistenceManager pm = PMF.get().getPersistenceManager();
		try
		{
			DBSpotInfo dbSpotInfo = getInfo(pm, spot.getId());
			String oldName=dbSpotInfo.getName();
			DBSpot dbSpot=getDBSpot(pm, dbSpotInfo.getSpot());
			DBSpotInfo newDbSpotInfo=DBUtil.pojo2db(spot, dbSpotInfo.getSpot());
			BeanUtils.copyProperties(dbSpotInfo, newDbSpotInfo);
			dbSpotInfo.setDate(new Date());
			dbSpotInfo.setAuthor(UserServiceFactory.getUserService().getCurrentUser());
			String tip=dbSpot.getName() + " > " + oldName + " => " + dbSpotInfo.getName();
			mailNotify("CHANGE: Website " + tip);
		}
		catch (IllegalAccessException e)
		{
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		catch (InvocationTargetException e)
		{
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		finally
		{
			pm.close();
		}
	}

	@Override
	public SpotInformation add(Spot spot, SpotInformation spotInfo)
	{
		PersistenceManager pm = PMF.get().getPersistenceManager();
		try
		{
			SpotInformation result = DBUtil.db2pojo(pm.makePersistent(DBUtil.pojo2db(spotInfo, spot.getId())));
			mailNotify("New: Website " + spot.getName() + " > " + spotInfo.getName());
			return result;
		}
		finally
		{
			pm.close();
		}
	}
	
//	@Override
//	public boolean isAdministrator()
//	{
//		return UserServiceFactory.getUserService().isUserAdmin();
//	}

	private List<DBSpot> getDBSpots(PersistenceManager pm)
	{
//		PersistenceManager pm = PMF.get().getPersistenceManager();
		Query query = pm.newQuery(DBSpot.class);
		try
		{
			return (List<DBSpot>) query.execute();
		}
		finally
		{
			query.closeAll();
//			pm.close();
		}
	}

	private DBSpot getDBSpot(PersistenceManager pm, Long id) {
//		String query = "select from " + DBSpot.class.getName() + " where id == " + id;
//		List<DBSpot> result = (List<DBSpot>) pm.newQuery(query).execute();
//		assert result.size()<=1;
//		return result.isEmpty() ? null : result.get(0);
        Key k = KeyFactory.createKey(DBSpot.class.getSimpleName(), id);
        return pm.getObjectById(DBSpot.class, k);
	}
	
	private List<DBSpotInfo> getInfos(PersistenceManager pm) {
//		String query = "select from " + DBSpotInfo.class.getName();
		return (List<DBSpotInfo>) pm.newQuery(DBSpotInfo.class).execute();
	}
	
	private DBSpotInfo getInfo(PersistenceManager pm, Long id) {
//		String query = "select from " + DBSpotInfo.class.getName() + " where id == " + id;
//		List<DBSpotInfo> result = (List<DBSpotInfo>) pm.newQuery(query).execute();
//		assert result.size()<=1;
//		return result.isEmpty() ? null : result.get(0);
////		return (List<DBSpotInfo>) pm.newQuery(query).execute();
		Key k = KeyFactory.createKey(DBSpotInfo.class.getSimpleName(), id);
        return pm.getObjectById(DBSpotInfo.class, k);
	}
	
	private List<DBSpotInfo> getInfos(PersistenceManager pm, Long spotId) {
		Query query = pm.newQuery(DBSpotInfo.class);
	    query.setFilter("spot == " + spotId);
	    try
	    {
//		String query = "select from " + DBSpotInfo.class.getName() + " where spot == " + spotId;
	    	return (List<DBSpotInfo>) pm.newQuery(query).execute();
	    }
	    finally
	    {
	    	query.closeAll();
	    }
	}
	
	private Spot createPontMaheSpot(String user, int index)
	{
		Spot spot=new Spot(-1, "Pont Mahe", true, user, null, null, index);
		int index2=0;
		spot.getInfos().add(new SpotInformation(-1, "Windguru", "http://www.windguru.cz/int/index.php?sc=714", true, user, index2++));
		spot.getInfos().add(new SpotInformation(-1, "Meteo France", "http://france.meteofrance.com/france/meteo?PREVISIONS_PORTLET.path=previsionsville%2F561950%2F", true, user, index2++));
		spot.getInfos().add(new SpotInformation(-1, "Wind Finder", "http://www.windfinder.com/forecast/pont_mah", true, user, index2++));
		spot.getInfos().add(new SpotInformation(-1, "Baston", "http://www.bastonv2.com/previsions-vent,mahe,MAH", true, user, index2++));
		spot.getInfos().add(new SpotInformation(-1, "Allo Surf", "http://www.allosurf.net/meteo-pont-mahe-surf-report-vent-96.html", true, user, index2++));
		spot.getInfos().add(new SpotInformation(-1, "Marees", "http://maree.frbateaux.net/111", true, user, index2++));
		return spot;
	}

	private Spot createMazerollesSpot(String user, int index)
	{
		Spot spot=new Spot(-1, "Mazerolles", true, user, null, null, index);
		int index2=0;
		spot.getInfos().add(new SpotInformation(-1, "Windguru", "http://www.windguru.cz/int/index.php?sc=54237", true, user, index2++));
		spot.getInfos().add(new SpotInformation(-1, "Meteo France", "http://france.meteofrance.com/france/meteo?PREVISIONS_PORTLET.path=previsionsville%2F441090%2F", true, user, index2++));
		spot.getInfos().add(new SpotInformation(-1, "Wind Finder", "http://www.windfinder.com/forecast/plaine_de_mazerolles_la_noue", true, user, index2++));
		spot.getInfos().add(new SpotInformation(-1, "Baston", "http://www.bastonv2.com/previsions-vent,mazerolles,MAZ", true, user, index2++));
		spot.getInfos().add(new SpotInformation(-1, "Cyanobacteries", "http://pagesperso-orange.fr/eden-sur-erdre/pages/pagesnav/infonav.htm", true, user, index2++));
		return spot;
	}
	
	protected void mailNotify(String msgBody)
	{
		UserService userService = UserServiceFactory.getUserService();
		if(!userService.isUserAdmin())
		{
			Properties props = new Properties();
			Session session = Session.getDefaultInstance(props, null);

			try {
				Message msg = new MimeMessage(session);
				msg.setFrom(new InternetAddress("christophe.moine@gmail.com"));
				msg.addRecipient(Message.RecipientType.TO, new InternetAddress("christophe.moine@gmail.com"));
				msg.setSubject("[Wind44] Change notification");
				User currentUser = userService.getCurrentUser();
				msg.setText(msgBody + "\nChange made by " + currentUser.getNickname());
				Transport.send(msg);
			} catch (AddressException e) {
				e.printStackTrace();
			} catch (MessagingException e) {
				e.printStackTrace();
			}
		}
	}
}
